package com.xyy.saas.payment.controller;

import com.xyy.framework.redis.core.RedisClient;
import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.api.impl.PaymentMerchantApiImpl;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.enums.*;
import com.xyy.saas.payment.cores.vo.*;
import com.xyy.saas.payment.dao.model.PayAccount;
import com.xyy.saas.payment.dao.model.UserInfo;
import com.xyy.saas.payment.service.UserInfoService;
import com.xyy.saas.payment.merchant.core.vo.*;
import com.xyy.saas.payment.service.PayAccountService;
import com.xyy.saas.payment.settle.core.service.AccountService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.TokenUtil;
import com.xyy.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import util.AESUtil;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author: wuqiongda
 * @Date: 2019/10/22 14:16
 */
/** 账户接口 */
@RestController
@RequestMapping(value = {"/api/account"})
public class AccountController {
    private static final Logger LOGGER = LoggerFactory.getLogger(AccountController.class);

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private AccountService accountService;

    @Autowired
    private TokenUtil tokenUtil;

    @Autowired
    private com.xyy.saas.payment.merchant.core.service.AccountService aggregateAccountService;

    @Resource
    private PaymentMerchantApiImpl paymentMerchantApi;

    @Autowired
    private PayAccountService payAccountService;

    @Autowired
    private UserInfoService userInfoService;

    /** 用户信息更新接口 - 不处理图片信息 */
    @RequestMapping(value = "/update/userinfo", method = {RequestMethod.POST}, produces = "application/json;charset=UTF-8")
    public ResultVO updateUserInfo(@RequestBody UserInfoUpdateVO param){
        ResultVO resultVO = new ResultVO();
        LOGGER.info("AccountController updateUserInfo begin UserInfoUpdateVO:{}", JSONUtils.toJSON(param));
        if (param==null|| StringUtil.isEmpty(param.getAccountId())){
            LOGGER.warn("AccountController updateUserInfo param error UserInfoUpdateVO:{}", JSONUtils.toJSON(param));
            return ResultVO.createParamError();
        }
        String accountId = param.getAccountId();
        UserInfo oldUserInfo = userInfoService.queryUserInfoByAccountId(accountId);
        if(null == oldUserInfo) {
            LOGGER.error("AccountController updateUserInfo user info is not exist. UserInfoUpdateVO:{}", JSONUtils.toJSON(param));
            return ResultVO.create(ResultCodeEnum.USER_NOT_FOUND);
        }
        // ============ 记录 避免误更 ===============
        LOGGER.info("AccountController updateUserInfo old user cipher info : {}", JSONUtils.toJSON(oldUserInfo));
        String telNo = null;
        List<ContactInfo> contactInfos = null;
        UserDto basicInfo = null;
        SettleAccountDto settleInfo = null;
        try {
            String userInfoKey = ApolloUtil.getProperty(Constants.USER_INFO_KEY);
            telNo = AESUtil.decrypt(oldUserInfo.getTelNo(), userInfoKey);
            String contactInfoStr = AESUtil.decrypt(oldUserInfo.getContactInfo(), userInfoKey);
            contactInfos = JSONUtils.parse2List(contactInfoStr, ContactInfo.class);
            String basicInfoStr = AESUtil.decrypt(oldUserInfo.getBasicInfo(), userInfoKey);
            basicInfo = JSONUtils.parse2Object(basicInfoStr, UserDto.class);
            String settleInfoStr = AESUtil.decrypt(oldUserInfo.getSettleInfo(), userInfoKey);
            settleInfo = JSONUtils.parse2Object(settleInfoStr, SettleAccountDto.class);
        } catch (Exception e) {
            LOGGER.error("AccountController updateUserInfo AESUtil.decrypt exception. e:{}", e);
            return ResultVO.create(ResultCodeEnum.DEFAULT_ERROR);
        }
        LOGGER.info("AccountController updateUserInfo old user data. telNo:{}, basicInfo:{}, settleInfo:{}, contactInfos:{}", telNo, JSONUtils.toJSON(basicInfo), JSONUtils.toJSON(settleInfo), JSONUtils.toJSON(contactInfos));
        // 数据替换
        // 电话号码
        if(StringUtils.isNotBlank(param.getMobile())) {
            telNo = param.getMobile();
        }
        // 这里直接替换
        if(null != param.getContactInfos() && !param.getContactInfos().isEmpty()) {
            contactInfos = param.getContactInfos();
        }
        // basicInfo
        if(StringUtils.isNotBlank(param.getName())) {
            basicInfo.setName(param.getName());
        }
        if(StringUtils.isNotBlank(param.getAddress())) {
            basicInfo.setAddress(param.getAddress());
        }
        // 身份信息
        if(StringUtils.isNotBlank(param.getCardId())) {
            basicInfo.getIdentityInfo().setId(param.getCardId());
        }
        if(StringUtils.isNotBlank(param.getIdentityType())) {
            basicInfo.getIdentityInfo().setType(param.getIdentityType());
        }
        if(StringUtils.isNotBlank(param.getProfession())) {
            basicInfo.getIdentityInfo().setProfession(param.getProfession());
        }
        if(StringUtils.isNotBlank(param.getValidFrom())) {
            basicInfo.getIdentityInfo().setValidFrom(param.getValidFrom());
        }
        if(StringUtils.isNotBlank(param.getValidUntil())) {
            basicInfo.getIdentityInfo().setValidUntil(param.getValidUntil());
        }
        if(StringUtils.isNotBlank(param.getIndustry())) {
            basicInfo.getIdentityInfo().setIndustry(param.getIndustry());
        }
        // 结算信息
        if(StringUtils.isNotBlank(param.getAccountType())) {
            settleInfo.setAccountType(param.getAccountType());
        }
        if(StringUtils.isNotBlank(param.getCallbackAddress())) {
            settleInfo.setCallbackAddress(param.getCallbackAddress());
        }
        if(StringUtils.isNotBlank(param.getBusinessUserName())) {
            settleInfo.setBusinessUserName(param.getBusinessUserName());
        }
        //
        if(StringUtils.isNotBlank(param.getAccount())) {
            settleInfo.getRecipient().setAccount(param.getAccount());
        }
        if(StringUtils.isNotBlank(param.getSettleName())) {
            settleInfo.getRecipient().setName(param.getSettleName());
        }
        if(StringUtils.isNotBlank(param.getSettleMobile())) {
            settleInfo.getRecipient().setMobile(param.getSettleMobile());
        }
        if(StringUtils.isNotBlank(param.getOpenBank())) {
            settleInfo.getRecipient().setOpenBank(param.getOpenBank());
        }
        if(StringUtils.isNotBlank(param.getSubBank())) {
            settleInfo.getRecipient().setSubBank(param.getSubBank());
        }
        if(StringUtils.isNotBlank(param.getSubBankCode())) {
            settleInfo.getRecipient().setSubBankCode(param.getSubBankCode());
        }
        if(StringUtils.isNotBlank(param.getCardType())) {
            settleInfo.getRecipient().setCardType(param.getCardType());
        }

        LOGGER.info("AccountController updateUserInfo new user data. telNo:{}, basicInfo:{}, settleInfo:{}, contactInfos:{}", telNo, JSONUtils.toJSON(basicInfo), JSONUtils.toJSON(settleInfo), JSONUtils.toJSON(contactInfos));
        try{
            //数据组装
            UserInfo userInfo = new UserInfo();
            userInfo.setContactInfo(AESUtil.encrypt(JSONUtils.toJSON(contactInfos), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            userInfo.setAccountId(accountId);
            userInfo.setTelNo(AESUtil.encrypt(telNo, ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            userInfo.setBasicInfo(AESUtil.encrypt(JSONUtils.toJSON(basicInfo), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            userInfo.setSettleInfo(AESUtil.encrypt(JSONUtils.toJSON(settleInfo), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            userInfo.setUtime(new Date());
            LOGGER.info("AccountController updateUserInfo new user cipher info : {}", JSONUtils.toJSON(userInfo));
            userInfoService.updateUserInfoByUserId(userInfo);
            return resultVO;
        }catch (Exception e){
            LOGGER.error("AccountController updateUserInfo error accountId:{}, e:{}", accountId, e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
    }

    /** 用户信息查询 */
    @RequestMapping(value = "/query/userinfo", method = {RequestMethod.GET}, produces = "application/json;charset=UTF-8")
    public ResultVO<UserInfoUpdateVO> queryUserInfo(@RequestParam String accountId){
        LOGGER.info("AccountController queryUserInfo begin accountId:{}", accountId);
        UserInfo oldUserInfo = userInfoService.queryUserInfoByAccountId(accountId);
        if(null == oldUserInfo) {
            LOGGER.error("AccountController queryUserInfo user info is not exist. accountId:{}", accountId);
            return ResultVO.create(ResultCodeEnum.USER_NOT_FOUND);
        }
        UserInfoUpdateVO result = new UserInfoUpdateVO();
        String telNo = null;
        Map<String, String> picMap = null;
        List<ContactInfo> contactInfos = null;
        UserDto basicInfo = null;
        SettleAccountDto settleInfo = null;
        try {
            String userInfoKey = ApolloUtil.getProperty(Constants.USER_INFO_KEY);
            telNo = AESUtil.decrypt(oldUserInfo.getTelNo(), userInfoKey);
            String contactInfoStr = AESUtil.decrypt(oldUserInfo.getContactInfo(), userInfoKey);
            picMap = JSONUtils.parse2Map(AESUtil.decrypt(oldUserInfo.getPicInfo(), userInfoKey), String.class, String.class);
            contactInfos = JSONUtils.parse2List(contactInfoStr, ContactInfo.class);
            String basicInfoStr = AESUtil.decrypt(oldUserInfo.getBasicInfo(), userInfoKey);
            basicInfo = JSONUtils.parse2Object(basicInfoStr, UserDto.class);
            String settleInfoStr = AESUtil.decrypt(oldUserInfo.getSettleInfo(), userInfoKey);
            settleInfo = JSONUtils.parse2Object(settleInfoStr, SettleAccountDto.class);
        } catch (Exception e) {
            LOGGER.error("AccountController queryUserInfo AESUtil.decrypt exception. e:{}", e);
            return ResultVO.create(ResultCodeEnum.DEFAULT_ERROR);
        }
        //
        result.setAccount(settleInfo.getRecipient().getAccount());
        result.setSettleName(settleInfo.getRecipient().getName());
        result.setSettleMobile(settleInfo.getRecipient().getMobile());
        result.setOpenBank(settleInfo.getRecipient().getOpenBank());
        result.setSubBank(settleInfo.getRecipient().getSubBank());
        result.setSubBankCode(settleInfo.getRecipient().getSubBankCode());
        result.setCardType(String.valueOf(settleInfo.getRecipient().getCardType()));
        result.setCallbackAddress(settleInfo.getCallbackAddress());
        result.setBusinessIdType(settleInfo.getBusinessIdType());
        result.setBusinessUserName(settleInfo.getBusinessUserName());
        result.setAccountType(settleInfo.getAccountType());

        result.setCardId(basicInfo.getIdentityInfo().getId());
        result.setIdentityType(basicInfo.getIdentityInfo().getType());
        result.setProfession(basicInfo.getIdentityInfo().getProfession());
        result.setValidFrom(basicInfo.getIdentityInfo().getValidFrom());
        result.setValidUntil(basicInfo.getIdentityInfo().getValidUntil());
        result.setIndustry(basicInfo.getIdentityInfo().getIndustry());

        result.setName(basicInfo.getName());
        result.setAddress(basicInfo.getAddress());

        result.setAccountId(accountId);
        result.setContactInfos(contactInfos);

        result.setMobile(telNo);

        result.setPicMap(picMap);
        return ResultVO.createSuccess(result);
    }

    /** 入驻数据缓存 */
    @RequestMapping(value = "/cache/settled/set", method = {RequestMethod.POST}, produces = "application/json;charset=UTF-8")
    public ResultVO cacheSettled(String token,
                                 String data,
                                 Long times,
                                 String businessIdType){
        ResultVO resultVO = new ResultVO();
        LOGGER.info("AccountController cacheSettled begin token:{}, businessIdType:{}", token, businessIdType);
        try{
            businessIdType = BusinessIdTypeEnum.valueOf(businessIdType).getType();
            String accountId = tokenUtil.checkUserToken(token, businessIdType);
            if (accountId==null){
                LOGGER.warn("AccountController cacheSettled token check error token:{}, businessIdType:{}", token, businessIdType);
                return ResultVO.createSignError();
            }
            redisClient.set(Constants.MERCHANT_ENTRY + accountId, data, times);
        }catch (Exception e){
            LOGGER.error("AccountController cacheSettled error token:{}, businessIdType:{}", token, businessIdType, e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
        LOGGER.info("AccountController cacheSettled end token:{}, businessIdType:{}", token, businessIdType);
        return ResultVO.createSuccess();
    }
    /** 获取入驻数据缓存 */
    @RequestMapping(value = "/cache/settled/query", method = {RequestMethod.POST}, produces = "application/json;charset=UTF-8")
    public ResultVO<String> queryCacheSettled(String token,
                                              String businessIdType){
        ResultVO resultVO = new ResultVO();
        LOGGER.info("AccountController queryCacheSettled begin token:{}, businessIdType:{}", token, businessIdType);
        try{
            businessIdType = BusinessIdTypeEnum.valueOf(businessIdType).getType();
            String accountId = tokenUtil.checkUserToken(token, businessIdType);
            if (accountId==null){
                LOGGER.warn("AccountController uploadPic4Address token check error token:{}, businessIdType:{}", token, businessIdType);
                return ResultVO.createSignError();
            }
            String data = redisClient.get(Constants.MERCHANT_ENTRY + accountId);
            resultVO.setResult(data);
        }catch (Exception e){
            LOGGER.error("AccountController queryCacheSettled error token:{}, BusinessIdType:{}", token, businessIdType, e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
        LOGGER.info("AccountController queryCacheSettled end token:{}, businessIdType:{}", token, businessIdType);
        return resultVO;
    }

    /** 账号查询 */
    @RequestMapping(value = "/queryAccount", method = RequestMethod.GET)
    public String queryAccount(@RequestParam String userId, @RequestParam String businessIdType) {
        return JSON.toJSONString(accountService.queryAccount(userId, businessIdType, AccountChannelEnum.AGGREGATE.getChannel(), BalanceAccountTypeEnum.FUND_ACCOUNT.getType()));
    }

    /** 创建合规账号账户 */
    @RequestMapping(value = "/createCPEAccount", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    public String createCPEAccount(@RequestParam String businessId, @RequestParam String businessIdType) throws Exception {
        AccountDto accountDto = new AccountDto();
        accountDto.setBusinessIdType(businessIdType);
        accountDto.setBusinessUserId(businessId);
        return JSONUtils.toJSON(accountService.createCPEAccount(accountDto));
    }

    /** 创建合规账号账户 */
    @RequestMapping(value = "/createAccount", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    public String createAccount(@RequestParam String businessId, @RequestParam String businessIdType) {
        AccountDto accountDto = new AccountDto();
        accountDto.setBusinessIdType(businessIdType);
        accountDto.setBusinessUserId(businessId);
        return JSONUtils.toJSON(accountService.createAccount(accountDto));
    }

    /** 聚合支付 开户+报件 */
    @RequestMapping(value = "/createAggregateAccount", method = {RequestMethod.POST})
    public ResultVO createAggregateAccount(@RequestBody com.xyy.saas.payment.merchant.core.dto.AccountDto accountDto) {
        try {
            return aggregateAccountService.createAccount(accountDto, StringUtils.EMPTY);
        }
        catch(Exception ex) {
            LOGGER.error(ex.getMessage() ,ex);
            return ex instanceof PaymentException ?
                    ResultVO.createError(ex.getMessage()) : ResultVO.create(ResultCodeEnum.DEFAULT_ERROR);
        }
    }

    /** 企业账户结算卡换绑 */
    @PostMapping(value = "/merchant/settleCardReBind", produces = "application/json;charset=UTF-8")
    public String merchantSettleCardReBind(@RequestBody MerchantSettleCardBindVo param) {
        return JSONUtils.toJSON(paymentMerchantApi.merchantSettleCardReBind(param, ""));
    }

    /** 个人账户结算卡换绑 */
    @PostMapping(value = "/personal/settleCardReBind", produces = "application/json;charset=UTF-8")
    public String personalSettleCardReBind(@RequestBody PersonalSettleCardBindVo param) {
        return JSON.toJSONString(paymentMerchantApi.personalSettleCardReBind(param, ""));
    }

    /** 个人账户富民单开户 */
    @RequestMapping(value = "/personal/fuminAccount", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public String fuminPersonAccount(@RequestBody PersonalAccountCreateVo param) {
        return JSON.toJSONString(paymentMerchantApi.personalCertifyAccountCreate(param, ""));
    }

    /** 企业账户富民单开户 */
    @RequestMapping(value = "/merchant/fuminAccount", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public String fuminMerchantAccount(@RequestBody MerchantAccountCreateVo param) {
        return JSON.toJSONString(paymentMerchantApi.merchantCertifyAccountCreate(param, ""));
    }

}
